package io.github.jsp.scheduler;



import io.github.jsp.dao.TaskMapper;
import io.github.jsp.model.Task;
import io.github.jsp.model.TaskExecution;
import io.github.jsp.util.CronExpressionUtil;
import io.github.jsp.util.ServerIdUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.lang.reflect.Constructor;
import java.util.Date;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

@Component
public class TaskScheduler {

    static final Logger log = LoggerFactory.getLogger(TaskScheduler.class);

    private ScheduledExecutorService scheduler;
    private final TaskMapper taskMapper;
    private final String serverId;
    
    @Autowired
    public TaskScheduler(TaskMapper taskMapper) {
        this.taskMapper = taskMapper;
        this.serverId = ServerIdUtil.getServerId();
        this.scheduler = Executors.newScheduledThreadPool(10);
    }
    
    @PostConstruct
    public void init() {
        log.info("Initializing task scheduler with server ID: {}", serverId);
        
        // 加载所有启用的任务
        List<Task> tasks = taskMapper.findAllEnabledTasks();
        for (Task task : tasks) {
            scheduleTask(task);
        }
        
        log.info("Task scheduler initialized with {} enabled tasks", tasks.size());
    }
    
    public void scheduleTask(Task task) {
        try {
            Date nextRunTime = CronExpressionUtil.getNextRunTime(task.getCronExpression());
            if (nextRunTime == null) {
                log.warn("Invalid cron expression for task: {}", task.getTaskName());
                return;
            }
            
            long delay = nextRunTime.getTime() - System.currentTimeMillis();
            if (delay < 0) {
                delay = 0;
            }
            
            log.debug("Scheduling task '{}' to run in {} ms", task.getTaskName(), delay);
            scheduler.schedule(() -> executeTask(task), delay, TimeUnit.MILLISECONDS);
        } catch (Exception e) {
            log.error("Error scheduling task: " + task.getTaskName(), e);
        }
    }
    
    private void executeTask(Task task) {
        // 尝试获取分布式锁
        try {
            log.debug("Attempting to acquire lock for task: {}", task.getTaskName());
            int acquired = taskMapper.acquireTaskLock(task.getId(), serverId);
            if (acquired <= 0) {
                // 未获取到锁，跳过执行
                log.debug("Failed to acquire lock for task: {}, skipping execution", task.getTaskName());
                scheduleTask(task); // 重新调度下一次执行
                return;
            }
            
            log.info("Executing task: {}", task.getTaskName());
            
            // 记录执行开始
            TaskExecution execution = new TaskExecution();
            execution.setTaskId(task.getId());
            execution.setServerId(serverId);
            execution.setStatus("RUNNING");
            taskMapper.recordTaskExecutionStart(execution);
            
            // 执行任务
            String result = "";
            try {
                // 通过反射实例化并执行任务
                Class<?> taskClass = Class.forName(task.getTaskClass());
                Constructor<?> constructor = taskClass.getConstructor();
                Runnable runnableTask = (Runnable) constructor.newInstance();
                runnableTask.run();
                
                execution.setStatus("SUCCESS");
                result = "Task executed successfully";
                log.info("Task {} executed successfully", task.getTaskName());
            } catch (Exception e) {
                execution.setStatus("FAILED");
                result = "Error: " + e.getMessage();
                log.error("Error executing task: " + task.getTaskName(), e);
            }
            
            // 更新执行结果
            execution.setResult(result);
            taskMapper.updateTaskExecutionResult(execution);
            
            // 释放锁
            taskMapper.releaseTaskLock(task.getId(), serverId);
            log.debug("Released lock for task: {}", task.getTaskName());
            
            // 调度下一次执行
            scheduleTask(task);
            
        } catch (Exception e) {
            log.error("Error in task execution process: " + task.getTaskName(), e);
            scheduleTask(task); // 出错时也要调度下一次执行
        }
    }
    
    @Scheduled(fixedRate = 60000) // 每分钟执行一次
    public void updateHeartbeats() {
        log.debug("Updating heartbeats for server: {}", serverId);
        try {
            // 更新当前服务器持有的所有锁的心跳时间
            // 具体实现依赖于数据库表设计
        } catch (Exception e) {
            log.error("Error updating heartbeats", e);
        }
    }
    
    @Scheduled(fixedRate = 300000) // 每5分钟执行一次
    public void cleanExpiredLocks() {
        log.debug("Cleaning expired locks");
        try {
            int count = taskMapper.cleanExpiredLocks();
            if (count > 0) {
                log.info("Cleaned {} expired locks", count);
            }
        } catch (Exception e) {
            log.error("Error cleaning expired locks", e);
        }
    }
    
    @PreDestroy
    public void shutdown() {
        log.info("Shutting down task scheduler");
        scheduler.shutdown();
        try {
            if (!scheduler.awaitTermination(60, TimeUnit.SECONDS)) {
                scheduler.shutdownNow();
            }
        } catch (InterruptedException e) {
            scheduler.shutdownNow();
            Thread.currentThread().interrupt();
        }
    }
}